#include "SyncManager.h"
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QCryptographicHash>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QHttpMultiPart>
#include <QFileSystemWatcher>
#include <QDebug>

namespace CollaborativeDesign {

SyncManager::SyncManager()
    : QObject(nullptr),
      m_syncDir(""),
      m_autoSyncInterval(60),
      m_autoSyncEnabled(false),
      m_serverUrl("http://localhost:8080/sync")
{
    // 连接自动同步定时器
    connect(&m_autoSyncTimer, &QTimer::timeout, this, &SyncManager::onAutoSyncTimer);
}

SyncManager::~SyncManager()
{
    // 停止自动同步
    m_autoSyncTimer.stop();
}

bool SyncManager::initialize(const QString& syncDir)
{
    // 设置同步目录
    m_syncDir = syncDir;
    
    // 确保同步目录存在
    QDir dir(m_syncDir);
    if (!dir.exists()) {
        if (!dir.mkpath(".")) {
            qWarning() << "无法创建同步目录:" << m_syncDir;
            return false;
        }
    }
    
    // 初始化文件监控
    initFileWatcher();
    
    // 加载同步项
    QDir syncDir(m_syncDir);
    QStringList files = syncDir.entryList(QDir::Files);
    
    for (const QString& file : files) {
        QString filePath = syncDir.absoluteFilePath(file);
        addSyncFile(filePath);
    }
    
    qDebug() << "初始化同步管理器成功:" << m_syncDir;
    return true;
}

bool SyncManager::addSyncFile(const QString& filePath)
{
    // 检查文件是否存在
    QFileInfo fileInfo(filePath);
    if (!fileInfo.exists() || !fileInfo.isFile()) {
        qWarning() << "文件不存在或不是文件:" << filePath;
        return false;
    }
    
    // 创建同步项
    SyncItem item;
    item.filePath = filePath;
    item.hash = calculateFileHash(filePath);
    item.lastSync = QDateTime::currentDateTime();
    item.lastModified = fileInfo.lastModified();
    item.status = SyncStatus::Idle;
    
    // 添加到同步项映射表
    m_syncItems[filePath] = item;
    
    qDebug() << "添加同步文件:" << filePath;
    return true;
}

bool SyncManager::removeSyncFile(const QString& filePath)
{
    // 检查文件是否在同步项中
    if (!m_syncItems.contains(filePath)) {
        qWarning() << "文件不在同步项中:" << filePath;
        return false;
    }
    
    // 从同步项映射表中移除
    m_syncItems.remove(filePath);
    
    qDebug() << "移除同步文件:" << filePath;
    return true;
}

SyncStatus SyncManager::getSyncStatus(const QString& filePath)
{
    // 检查文件是否在同步项中
    if (!m_syncItems.contains(filePath)) {
        return SyncStatus::Error;
    }
    
    return m_syncItems[filePath].status;
}

bool SyncManager::syncNow(const QString& filePath)
{
    // 如果指定了文件路径，只同步该文件
    if (!filePath.isEmpty()) {
        if (!m_syncItems.contains(filePath)) {
            qWarning() << "文件不在同步项中:" << filePath;
            return false;
        }
        
        // 发送同步开始信号
        emit syncStarted(filePath);
        
        // 更新同步状态
        m_syncItems[filePath].status = SyncStatus::Syncing;
        emit syncStatusChanged(filePath, SyncStatus::Syncing);
        
        // 执行增量同步
        bool success = incrementalSync(filePath);
        
        // 更新同步状态
        m_syncItems[filePath].status = success ? SyncStatus::Idle : SyncStatus::Error;
        emit syncStatusChanged(filePath, m_syncItems[filePath].status);
        
        // 发送同步完成信号
        emit syncCompleted(filePath, success);
        
        return success;
    }
    
    // 同步所有文件
    bool allSuccess = true;
    
    for (auto it = m_syncItems.begin(); it != m_syncItems.end(); ++it) {
        QString currentFilePath = it.key();
        
        // 发送同步开始信号
        emit syncStarted(currentFilePath);
        
        // 更新同步状态
        it.value().status = SyncStatus::Syncing;
        emit syncStatusChanged(currentFilePath, SyncStatus::Syncing);
        
        // 执行增量同步
        bool success = incrementalSync(currentFilePath);
        
        // 更新同步状态
        it.value().status = success ? SyncStatus::Idle : SyncStatus::Error;
        emit syncStatusChanged(currentFilePath, it.value().status);
        
        // 发送同步完成信号
        emit syncCompleted(currentFilePath, success);
        
        if (!success) {
            allSuccess = false;
        }
    }
    
    return allSuccess;
}

bool SyncManager::resolveConflict(const QString& filePath, bool useLocal)
{
    // 检查文件是否在同步项中
    if (!m_syncItems.contains(filePath)) {
        qWarning() << "文件不在同步项中:" << filePath;
        return false;
    }
    
    // 检查文件是否有冲突
    if (m_syncItems[filePath].status != SyncStatus::Conflict) {
        qWarning() << "文件没有冲突:" << filePath;
        return false;
    }
    
    if (useLocal) {
        // 使用本地文件解决冲突
        bool success = uploadFile(filePath);
        
        // 更新同步状态
        m_syncItems[filePath].status = success ? SyncStatus::Idle : SyncStatus::Error;
        emit syncStatusChanged(filePath, m_syncItems[filePath].status);
        
        return success;
    } else {
        // 使用远程文件解决冲突
        bool success = downloadFile(filePath);
        
        // 更新同步状态
        m_syncItems[filePath].status = success ? SyncStatus::Idle : SyncStatus::Error;
        emit syncStatusChanged(filePath, m_syncItems[filePath].status);
        
        return success;
    }
}

QList<SyncItem> SyncManager::getAllSyncItems()
{
    return m_syncItems.values();
}

void SyncManager::setAutoSyncInterval(int seconds)
{
    m_autoSyncInterval = seconds;
    
    // 如果自动同步已启用，重新启动定时器
    if (m_autoSyncEnabled) {
        m_autoSyncTimer.start(m_autoSyncInterval * 1000);
    }
}

void SyncManager::setAutoSync(bool enable)
{
    m_autoSyncEnabled = enable;
    
    if (enable) {
        // 启动自动同步定时器
        m_autoSyncTimer.start(m_autoSyncInterval * 1000);
    } else {
        // 停止自动同步定时器
        m_autoSyncTimer.stop();
    }
}

void SyncManager::onAutoSyncTimer()
{
    // 执行自动同步
    syncNow();
}

void SyncManager::onFileChanged(const QString& filePath)
{
    // 检查文件是否在同步项中
    if (!m_syncItems.contains(filePath)) {
        return;
    }
    
    // 检查文件是否真的变更
    if (!isFileChanged(filePath)) {
        return;
    }
    
    // 更新文件信息
    QFileInfo fileInfo(filePath);
    m_syncItems[filePath].lastModified = fileInfo.lastModified();
    m_syncItems[filePath].hash = calculateFileHash(filePath);
    
    // 如果自动同步已启用，执行同步
    if (m_autoSyncEnabled) {
        syncNow(filePath);
    }
}

QByteArray SyncManager::calculateFileHash(const QString& filePath)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly)) {
        qWarning() << "无法打开文件计算哈希:" << filePath;
        return QByteArray();
    }
    
    QCryptographicHash hash(QCryptographicHash::Sha256);
    hash.addData(&file);
    
    return hash.result();
}

bool SyncManager::isFileChanged(const QString& filePath)
{
    // 检查文件是否在同步项中
    if (!m_syncItems.contains(filePath)) {
        return false;
    }
    
    // 计算当前文件哈希
    QByteArray currentHash = calculateFileHash(filePath);
    
    // 比较哈希值
    return currentHash != m_syncItems[filePath].hash;
}

bool SyncManager::uploadFile(const QString& filePath)
{
    // 检查文件是否存在
    QFileInfo fileInfo(filePath);
    if (!fileInfo.exists() || !fileInfo.isFile()) {
        qWarning() << "文件不存在或不是文件:" << filePath;
        return false;
    }
    
    // 创建网络请求
    QNetworkAccessManager manager;
    QNetworkRequest request(QUrl(m_serverUrl + "/upload"));
    
    // 创建多部分表单数据
    QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    
    // 添加文件路径
    QHttpPart pathPart;
    pathPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"path\""));
    pathPart.setBody(filePath.toUtf8());
    multiPart->append(pathPart);
    
    // 添加文件数据
    QHttpPart filePart;
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"file\"; filename=\"" + fileInfo.fileName() + "\""));
    
    QFile* file = new QFile(filePath);
    if (!file->open(QIODevice::ReadOnly)) {
        qWarning() << "无法打开文件进行上传:" << filePath;
        delete multiPart;
        delete file;
        return false;
    }
    
    filePart.setBodyDevice(file);
    file->setParent(multiPart);
    multiPart->append(filePart);
    
    // 发送请求
    QNetworkReply* reply = manager.post(request, multiPart);
    multiPart->setParent(reply);
    
    // 等待请求完成
    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec();
    
    // 检查响应
    if (reply->error() != QNetworkReply::NoError) {
        qWarning() << "上传文件失败:" << reply->errorString();
        reply->deleteLater();
        return false;
    }
    
    // 更新同步项信息
    m_syncItems[filePath].lastSync = QDateTime::currentDateTime();
    
    reply->deleteLater();
    return true;
}

bool SyncManager::downloadFile(const QString& filePath)
{
    // 创建网络请求
    QNetworkAccessManager manager;
    QNetworkRequest request(QUrl(m_serverUrl + "/download"));
    
    // 添加文件路径参数
    QUrl url(m_serverUrl + "/download");
    QUrlQuery query;
    query.addQueryItem("path", filePath);
    url.setQuery(query);
    request.setUrl(url);
    
    // 发送请求
    QNetworkReply* reply = manager.get(request);
    
    // 等待请求完成
    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec();
    
    // 检查响应
    if (reply->error() != QNetworkReply::NoError) {
        qWarning() << "下载文件失败:" << reply->errorString();
        reply->deleteLater();
        return false;
    }
    
    // 保存文件
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly)) {
        qWarning() << "无法打开文件进行写入:" << filePath;
        reply->deleteLater();
        return false;
    }
    
    file.write(reply->readAll());
    file.close();
    
    // 更新同步项信息
    QFileInfo fileInfo(filePath);
    m_syncItems[filePath].lastSync = QDateTime::currentDateTime();
    m_syncItems[filePath].lastModified = fileInfo.lastModified();
    m_syncItems[filePath].hash = calculateFileHash(filePath);
    
    reply->deleteLater();
    return true;
}

bool SyncManager::detectConflict(const QString& filePath)
{
    // 创建网络请求
    QNetworkAccessManager manager;
    QNetworkRequest request(QUrl(m_serverUrl + "/check"));
    
    // 添加文件路径参数
    QUrl url(m_serverUrl + "/check");
    QUrlQuery query;
    query.addQueryItem("path", filePath);
    url.setQuery(query);
    request.setUrl(url);
    
    // 发送请求
    QNetworkReply* reply = manager.get(request);
    
    // 等待请求完成
    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec();
    
    // 检查响应
    if (reply->error() != QNetworkReply::NoError) {
        qWarning() << "检查文件冲突失败:" << reply->errorString();
        reply->deleteLater();
        return false;
    }
    
    // 解析响应
    QByteArray data = reply->readAll();
    QJsonDocument doc = QJsonDocument::fromJson(data);
    
    if (doc.isNull() || !doc.isObject()) {
        qWarning() << "无效的JSON响应";
        reply->deleteLater();
        return false;
    }
    
    QJsonObject obj = doc.object();
    bool hasConflict = obj["conflict"].toBool();
    
    if (hasConflict) {
        // 更新同步状态
        m_syncItems[filePath].status = SyncStatus::Conflict;
        emit syncStatusChanged(filePath, SyncStatus::Conflict);
        
        // 发送冲突检测信号
        emit conflictDetected(filePath);
    }
    
    reply->deleteLater();
    return hasConflict;
}

bool SyncManager::incrementalSync(const QString& filePath)
{
    // 检查文件是否在同步项中
    if (!m_syncItems.contains(filePath)) {
        qWarning() << "文件不在同步项中:" << filePath;
        return false;
    }
    
    // 检查文件是否有冲突
    if (detectConflict(filePath)) {
        qWarning() << "文件有冲突:" << filePath;
        return false;
    }
    
    // 检查文件是否变更
    if (isFileChanged(filePath)) {
        // 上传文件
        return uploadFile(filePath);
    } else {
        // 下载文件
        return downloadFile(filePath);
    }
}

void SyncManager::initFileWatcher()
{
    // 创建文件系统监控器
    QFileSystemWatcher* watcher = new QFileSystemWatcher(this);
    
    // 监控同步目录
    watcher->addPath(m_syncDir);
    
    // 连接信号
    connect(watcher, &QFileSystemWatcher::fileChanged, this, &SyncManager::onFileChanged);
    connect(watcher, &QFileSystemWatcher::directoryChanged, this, [this, watcher](const QString& path) {
        // 目录变更时，更新监控的文件
        QDir dir(path);
        QStringList files = dir.entryList(QDir::Files);
        
        for (const QString& file : files) {
            QString filePath = dir.absoluteFilePath(file);
            
            // 如果文件不在监控列表中，添加到监控
            if (!watcher->files().contains(filePath)) {
                watcher->addPath(filePath);
                
                // 如果文件不在同步项中，添加到同步项
                if (!m_syncItems.contains(filePath)) {
                    addSyncFile(filePath);
                }
            }
        }
    });
}

} // namespace CollaborativeDesign 